package com.derbysoft.defender.mp.api.requester;

import com.derbysoft.defender.mp.api.response.AccessToken;

/**
 * <p>
 * 公众平台接口域名说明
 * 开发者可以根据自己的服务器部署情况，选择最佳的接入点（延时更低，稳定性更高）。除此之外，可以将其他接入点用作容灾用途，
 * 当网络链路发生故障时，可以考虑选择备用接入点来接入。
 * 1. 通用域名(api.weixin.qq.com)，使用该域名将访问官方指定就近的接入点；
 * 2. 上海域名(sh.api.weixin.qq.com)，使用该域名将访问上海的接入点；
 * 3. 深圳域名(sz.api.weixin.qq.com)，使用该域名将访问深圳的接入点；
 * 4. 香港域名(hk.api.weixin.qq.com)，使用该域名将访问香港的接入点。
 * </p>
 * <p>
 * 获取access_token，每日限额2000次。
 * </p>
 * <p>
 * access_token是公众号的全局唯一接口调用凭据，公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。
 * access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时，需定时刷新，重复获取将导致上次获取的access_token失效。
 * </p>
 * <p>
 * 公众平台的API调用所需的access_token的使用及生成方式说明：
 * 1、为了保密appsecrect，第三方需要一个access_token获取和刷新的中控服务器。而其他业务逻辑服务器所使用的access_token均来自于该中控服务器，不应该各自去刷新，否则会造成access_token覆盖而影响业务；
 * 2、目前access_token的有效期通过返回的expire_in来传达，目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中，中控服务器对外输出的依然是老access_token，
 * 此时公众平台后台会保证在刷新短时间内，新老access_token都可用，这保证了第三方业务的平滑过渡；
 * 3、access_token的有效时间可能会在未来有调整，所以中控服务器不仅需要内部定时主动刷新，
 * 还需要提供被动刷新access_token的接口，这样便于业务服务器在API调用获知access_token已超时的情况下，可以触发access_token的刷新流程。
 * </p>
 * <p/>
 * Created by Afee Lee on 2017-03-19 15:48
 *
 * @author Afee Lee
 * @version 1.0
 * @see Object
 * @since 1.8
 */
public class AccessTokenRequester extends AbstractRequester {
    private static final String DEFAULT_URL = "https://api.weixin.qq.com/cgi-bin/token" +
            "?grant_type={grant_type}&appid={appid}&secret={secret}";

    private String url = DEFAULT_URL;
    private String grantType = "client_credential";
    private String appId;
    private String appSecret;

    private AccessTokenRequester() {
    }

    public AccessTokenRequester(String appId, String appSecret) {
        this.appId = appId;
        this.appSecret = appSecret;
    }

    public String getUrl() {
        return url;
    }

    public String getGrantType() {
        return grantType;
    }

    public String getAppId() {
        return appId;
    }

    public String getAppSecret() {
        return appSecret;
    }

    public AccessTokenRequester setUrl(String url) {
        this.url = url;
        return this;
    }

    public AccessTokenRequester setGrantType(String grantType) {
        this.grantType = grantType;
        return this;
    }

    public AccessToken request() {
        return getForEntity(url, AccessToken.class, grantType, appId, appSecret)
                .initExpires();
    }
}
